package com.bytech.common.utils;

import java.io.File;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.util.CollectionUtils;

import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * @Author Zhao
 * @Create 2021/7/22 17:28
 */
@Slf4j
public class OkHttpUtil {

    /**
     * get请求
     */
    public static String get(String url, List<Pair<String, String>> queries) {
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .url(sb.toString())
                .build();
        return execNewCall(request);
    }

    /**
     * get 带 header 版本
     */
    public static String get(String url, List<Pair<String, String>> queries, Map<String, String> headerMap) {
        Headers.Builder hb = new Headers.Builder();
        headerMap.keySet().forEach(k -> {
            hb.add(k, headerMap.get(k));
        });
        StringBuffer sb = getQueryString(url, queries);
        Request request = new Request.Builder()
                .headers(hb.build())
                .url(sb.toString())
                .build();
        return execNewCall(request);
    }

    /**
     * post
     */
    public static String postFormParams(String url, Map<String, String> params) {
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        return execNewCall(request);
    }

    /**
     * Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"}
     * 参数一：请求Url
     * 参数二：请求的JSON
     * 参数三：请求回调
     */
    public static String postJsonParams(String url, String jsonParams) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return execNewCall(request);
    }

    /**
     * Post请求发送xml数据....
     * 参数一：请求Url
     * 参数二：请求的xmlString
     * 参数三：请求回调
     */
    public static String postXmlParams(String url, String xml) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return execNewCall(request);
    }

    /**
     * 通过 multipart 上传文件（带 header 版本）
     *
     * @param url     请求路径
     * @param headers 请求头
     * @param files   上传文件
     * @param path    文件保存路径
     */
    public static String postFiles(String url, Map<String, String> headers, List<File> files, String path) {
        if (CollectionUtils.isEmpty(files) || StringUtils.isBlank(url)) {
            return null;
        }
        MultipartBody.Builder mpBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (File file : files) {
            if (file == null) {
                continue;
            }
            Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"files\"; filename=\"" + file.getName() + "\"");
            MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file));
            mpBuilder.addPart(partHeaders, RequestBody.create(mediaType, file));
        }
        List<Pair<String, String>> params = Lists.newArrayList();
        params.add(Pair.of("path", path));
        Request.Builder reqBuilder = new Request.Builder().url(getQueryString(url, params).toString());
        if (!CollectionUtils.isEmpty(headers)) {
            for (Entry<String, String> param : headers.entrySet()) {
                reqBuilder.header(param.getKey(), param.getValue());
            }
        }
        return execNewCall(reqBuilder.method("POST", mpBuilder.build()).build());
    }

    /**
     * 通过 multipart 上传文件
     */
    public static String postFiles(String url, List<File> files, String path) {
        return postFiles(url, null, files, path);
    }

    public static String guessContentTypeFromFile(File file) {
        String contentType = URLConnection.guessContentTypeFromName(file.getName());
        if (contentType == null) {
            return "application/octet-stream";
        } else {
            return contentType;
        }
    }

    /**
     * 根据map获取get请求参数
     */
    public static StringBuffer getQueryString(String url, List<Pair<String, String>> queries) {
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.size() > 0) {
            boolean firstFlag = true;
            for (Pair<String, String> query : queries) {
                if (firstFlag) {
                    sb.append("?").append(query.getLeft()).append("=").append(query.getRight());
                    firstFlag = false;
                } else {
                    sb.append("&").append(query.getLeft()).append("=").append(query.getRight());
                }
            }
        }
        return sb;
    }

    /**
     * 调用okhttp的newCall方法
     */
    private static String execNewCall(Request request) {
        Response response = null;
        try {
            OkHttpClient okHttpClient = ApplicationBeanUtils.getBean(OkHttpClient.class);
            response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return Objects.requireNonNull(response.body()).string();
            }
        } catch (Exception e) {
            log.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return "";
    }
}